#include "copycat.h"


bool CCopycatTest::LoadRuleCR( char *dir, int cross_red_th )
{
	rule_cross.Clear();
	CUString fn = dir; fn += "/rule.cr";
	if( rule_cross.LoadRule( fn.GetStr(), cross_red_th ) == false )	{
		return false;
	}
	else {
		fprintf( stderr, "[CR] %d rules loaded\n", rule_cross.GetNumRules() );
	}

	return true;
}

bool CCopycatTest::LoadInsRule( char *dir, int freq_th, double prob_th )
{
	ins_rule.Clear();
	CUString fn = dir; fn += "/ins.rule";
	if( ins_rule.LoadRule( fn.GetStr(), freq_th, prob_th ) == false )	{
		return false;
	}
	else {
		fprintf( stderr, "[INS] %d rules loaded\n", ins_rule.GetNumRules() );
	}

	return true;
}


bool CCopycatTest::LoadRuleRF( char *dir, int freq_th, double prob_th )
{
	rule_rf.Clear();
	CUString fn = dir; fn += "/rule.rf";
	if( rule_rf.LoadRule( fn.GetStr(), freq_th, prob_th ) == false )	{
		return false;
	}
	else {
		fprintf( stderr, "[RF] %d rules loaded\n", rule_rf.GetNumRules() );
	}

	return true;
}

//////////////////////////////////////////////////////////////////////////////
bool CCopycatTest::ApplyRule( char *in_fn, char *tok_fn, char *out_dir, CUString type )
{
	char cmd[1024];
	sprintf( cmd, "mkdir -p %s", out_dir );	system( cmd );


	// open files
	CUTextFile parse_file( in_fn, "r" );
	if( parse_file.IsOpen() == false )	{
		fprintf( stderr, "ERROR: file open fail %s\n", in_fn );
		return false;	
	}

	CUTextFile tok_file( tok_fn, "r" );
	if( tok_file.IsOpen() == false )	{
		fprintf( stderr, "ERROR: file open fail %s\n", tok_fn );
		return false;	
	}

	CUString out_fn = CUString(out_dir) + CUString("/src.SP" );
	CUTextFile out_file_sp( out_fn, "w" );

	CUString out_fn2 = CUString(out_dir) + CUString("/src.parse" );
	CUTextFile out_file_parse( out_fn2, "w" );

	CUString out_fn3 = CUString(out_dir) + CUString("/src.rinfo" );
	CUTextFile out_file_rinfo( out_fn3, "w" );


	fprintf( stderr, "Applying Rules %s...\n",type.GetStr() );
	int num_line = parse_file.GetNumLine(); parse_file.MoveToStart();
	num_sent = 0;
	int num_node = 0;
	int num_reorder = 0;

	while(1)	{
		CUString line;
		if( parse_file.ReadLine( line ) == false )	break;
		line.Replace("\r", "" );

		CUString tok_line;
		if( tok_file.ReadLine( tok_line ) == false )	break;
		num_sent++;
		
		//if( num_sent % 10000 == 0 )		fprintf( stderr, "." );
		fprintf( stderr, "\r%d / %d ", num_sent, num_line );

		if( line.GetLength() == 0 )	{
			fprintf( stdout, "\nERROR: null line %d\n", num_sent );	return false;
		}


		// load parse string
		CSent s;
		s.parse = line;
		s.id = num_sent;

		// load tree
		CTree t;
		t.Init();
		if( t.LoadTree( s.parse ) == false )	{

			fprintf( out_file_sp.GetFP(), "%s\n", tok_line.GetStr() );
			CUStringListSN tlist( tok_line, " " );
			for( int i=0; i< tlist.GetSize(); i++ )	{
				if( i>0 )	{
					fprintf( out_file_rinfo.GetFP(), " " );
				}
				fprintf( out_file_rinfo.GetFP(), "%d", i );
			}
			fprintf( out_file_rinfo.GetFP(), "\n" );
			fprintf( out_file_parse.GetFP(), "%s\n", line.GetStr() );

			continue;
			return false;
		}

		ReorderRule( t, num_reorder, num_node, type );

		// print
		PrintReorderedSent( t, out_file_sp.GetFP(), out_file_parse.GetFP(), out_file_rinfo.GetFP() );

	}
	fprintf( stderr, "\r%d sentences processed.\n", num_sent );
	fprintf( stderr, "%d out of %d nodes are reordered.\n", num_reorder, num_node );

	// print used rules
	char buf[1024];
	if( type == "CR" )	{
		sprintf( buf, "%s/applied_rules.cr",out_dir );
		FILE *fp = fopen( buf, "w" );
		rule_cross.SaveToFile( fp, stree );
		fclose( fp );
	}
	else if ( type == "RF" )	{
		sprintf( buf, "%s/applied_rules.rf",out_dir );
		FILE *fp = fopen( buf, "w" );
		rule_rf.SaveToFile( fp, stree, true );
		fclose( fp );
	}

	FILE *info_fp = NULL;
	sprintf( buf, "%s/info.txt", out_dir );
	info_fp = fopen ( buf, "w" );
	if( type == "CR" )	{
		fprintf( info_fp, "num_rules\t%d\n", rule_cross.GetNumRules() );
	}
	else if( type == "RF" )	{
		fprintf( info_fp, "num_cand_rules\t%d\n", rule_rf.GetNumRules() );
		fprintf( info_fp, "num_best_rules\t%d\n", rule_rf.GetNumBestReorderRules() );
	}

	fprintf( info_fp, "num_reordered_node\t%d\n", num_reorder );
	fprintf( info_fp, "num_node\t%d\n", num_node );
	fprintf( info_fp, "ratio\t%1.4f\n", (double)num_reorder/(double)num_node );
	fclose( info_fp );

	return true;
}


//////////////////////////////////////////////////////////////////////////////
bool CCopycatTest::ApplyInsRule( char *in_fn, char *out_dir, CUString type )
{
//	copyopt.depth=2;

	char cmd[1024];
	sprintf( cmd, "mkdir -p %s", out_dir );	system( cmd );


	// open files
	CUTextFile parse_file( in_fn, "r" );
	if( parse_file.IsOpen() == false )	{
		fprintf( stderr, "ERROR: file open fail %s\n", in_fn );
		return false;	
	}

	CUString out_fn = CUString(out_dir) + CUString("/src.SP" );
	CUTextFile out_file_sp( out_fn, "w" );

	CUString out_fn2 = CUString(out_dir) + CUString("/src.parse" );
	CUTextFile out_file_parse( out_fn2, "w" );

	CUString out_fn3 = CUString(out_dir) + CUString("/src.copyinfo" );
	CUTextFile out_file_copyinfo( out_fn3, "w" );


	fprintf( stderr, "Applying Insert Rules...\n" );
	int num_line = parse_file.GetNumLine(); parse_file.MoveToStart();
	num_sent = 0;
	int num_node = 0;
	int num_insert = 0;

	while(1)	{
		CUString line;
		if( parse_file.ReadLine( line ) == false )	break;
		line.Replace("\r", "" );
		num_sent++;
		
		//if( num_sent % 10000 == 0 )		fprintf( stderr, "." );
		fprintf( stderr, "\r%d / %d ", num_sent, num_line );

		if( line.GetLength() == 0 )	{
			fprintf( stdout, "\nERROR: null line %d\n", num_sent );	return false;
		}


		// load parse string
		CSent s;
		s.parse = line;
		s.id = num_sent;

		// load tree
		CTree t;
		t.Init();
		if( t.LoadTree( s.parse ) == false )	return false;

		Insert( t, num_insert, num_node, type );
		/*
		ReorderRule( t, num_reorder, num_node, type );
		*/

		// print
		PrintInsertedSent( t, out_file_sp.GetFP(), out_file_parse.GetFP(), out_file_copyinfo.GetFP() );

	}

	fprintf( stderr, "\r%d sentences processed.\n", num_sent );
	//fprintf( stderr, "%d out of %d nodes are reordered.\n", num_reorder, num_node );

	// print used rules
	char buf[1024];
	sprintf( buf, "%s/applied_ins.rule",out_dir );
	FILE *fp = fopen( buf, "w" );
	ins_rule.SaveToFile( fp, stree, true );
	fclose( fp );

	/*
	sprintf( buf, "%s/info.txt", out_dir );
	FILE *info_fp = fopen ( buf, "w" );
	if( type == "CR" )	{
		fprintf( info_fp, "num_rules\t%d\n", rule_cross.GetNumRules() );
	}
	else if( type == "RF" )	{
		fprintf( info_fp, "num_cand_rules\t%d\n", rule_rf.GetNumRules() );
		fprintf( info_fp, "num_best_rules\t%d\n", rule_rf.GetNumBestReorderRules() );
	}

	fprintf( info_fp, "num_reordered_node\t%d\n", num_reorder );
	fprintf( info_fp, "num_node\t%d\n", num_node );
	fprintf( info_fp, "ratio\t%1.4f\n", (double)num_reorder/(double)num_node );
	fclose( info_fp );
	*/


	return true;
}


//////////////////////////////////////////////////////////////////////////////
bool CCopycatTest::Insert( CTree &t, int &num_insert, int &num_node, CUString type )
{
	int ls[NUM_MAX_NODE];
	int s;
	t.GetTraverseList( ls, s, ROOT_ID );

	for( int i=0; i<s; i++ )	{
		CNode &n = t.node[ ls[i] ];
		num_node++;

		/*
		if( MCH == "2" )	{ if( n.num_child != 2 )	continue; }
		else if( MCH == "23" )	 { if( n.num_child == 2  || n.num_child ==3 )	{ } else	{ continue; } }
		else { if( n.num_child <= 1 ) continue;  }
		*/



		CUString rule_str = GetSubtreeStr( t, n );
		CUStringList after_list;


		CInsertRule rule[1024];
		int num_rule=0;
		if( ins_rule.FindRule( rule_str, rule, num_rule ) == false )	continue;
		CInsertRule &best_rule = rule[0];
		after_list.TokenizeByStr( best_rule.after, " ", false );


		int curr_child = 0;
		bool have_insert = false;
		for( int j=0; j<after_list.GetSize(); j++ )	{
			CUString copyinfo = after_list.GetAt(j);

			if( copyinfo.GetAt(0) == 'A' )	{
				curr_child++;
				continue;
			}
			else if( copyinfo.GetAt(0) == 'I' )	{

				for( int k=n.num_child-1; k >= curr_child; k-- )	{
					n.child[ k+1 ] = n.child[ k ];

				}
				n.num_child++;


				copyinfo.TrimLeft("I");
				int tmp_idx = copyinfo.ReverseFind('/');
				CUString lex = copyinfo.Left(  tmp_idx );
				CUString pos = copyinfo.Mid( tmp_idx+1 );

				// pos node
				int pos_node_id = t.num_node; (t.num_node)++;

				CNode &pos_node = t.node[ pos_node_id ];
				pos_node.label = pos;
				pos_node.id = pos_node_id;
				pos_node.parent = n.id;
				
				n.child[ curr_child ] = pos_node_id; curr_child++;
				//n.child[ n.num_child ] = pos_node_id; n.num_child++;
				pos_node.level = n.level+1;

				// lex node
				int lex_node_id = t.num_node; (t.num_node)++;

				CNode &lex_node = t.node[ lex_node_id ];
				lex_node.label = lex;
				lex_node.id = lex_node_id;
				lex_node.parent = pos_node.id;

				pos_node.child[ pos_node.num_child ] = lex_node_id; pos_node.num_child++;
				lex_node.level = pos_node.level+1;


				have_insert = true;
			}
		}
		if( have_insert == true )	num_insert++;
	}

	return true;
}

//////////////////////////////////////////////////////////////////////////////
bool CCopycatTest::ReorderRule( CTree &t, int &num_reorder, int &num_node, CUString type )
{
	int ls[NUM_MAX_NODE];
	int s;
	t.GetTraverseList( ls, s, ROOT_ID );

	for( int i=0; i<s; i++ )	{
		CNode &n = t.node[ ls[i] ];
		num_node++;

		if( MCH == "2" )	{ if( n.num_child != 2 )	continue; }
		else if( MCH == "23" )	 { if( n.num_child == 2  || n.num_child ==3 )	{ } else	{ continue; } }
		else { if( n.num_child <= 1 ) continue;  }



		CUString rule_str = GetSubtreeStr( t, n );
		CUStringList after_list;

		if( type == "CR" )	{
			CRuleCross rule[1024];
			int num_rule=0;
			if( rule_cross.FindRule( rule_str, rule, num_rule ) == false )	continue;
			CRuleCross &best_rule = rule[0];
			after_list.TokenizeByStr( best_rule.after, " ", false );
		}
		else if( type == "RF" )	{
			CRuleRF rule[1024];
			int num_rule=0;
			if( rule_rf.FindRule( rule_str, rule, num_rule ) == false )	continue;
			CRuleRF &best_rule = rule[0];
			after_list.TokenizeByStr( best_rule.after, " ", false );
		}

		if( n.num_child != after_list.GetSize() )	{
			fprintf( stderr, "diff %d %d\n", n.num_child, after_list.GetSize() );
			return false;
			continue;
		}

		bool have_reorder = false;
		for( int j=0; j<after_list.GetSize(); j++ )	{
			CUString left = after_list.GetAt(j);
			left.TrimLeft( "A" );
			int left_idx = atoi( left.GetStr() );

			for( int k=j+1; k<after_list.GetSize(); k++ )	{
				CUString right = after_list.GetAt(k);
				right.TrimLeft( "A" );
				int right_idx = atoi( right.GetStr() );

				if( left_idx > right_idx )	{
					int tmp = n.child[j];
					n.child[j] = n.child[k];
					n.child[k] = tmp;
					have_reorder = true;
				}


			}

		}
		if( have_reorder == true )	num_reorder++;

	}

	return true;
}

//////////////////////////////////////////////////////////////////////////////
bool CCopycatTest::PrintInsertedSent( CTree &t, FILE *tok_fp, FILE *parse_fp, FILE *copyinfo_fp )
{
	int ls[NUM_MAX_NODE];
	int s;

	t.GetLexNodeList( ls, s, ROOT_ID );
	for( int i=0; i<s; i++ )	{
		CNode &n = t.node[ ls[i] ];
		CNode &p = t.node[ n.parent ];

		if( i > 0 )	{
			fprintf( tok_fp, " " );
			fprintf( copyinfo_fp, " " );
		}
		fprintf( tok_fp, "%s/%s", n.label.GetStr(), p.label.GetStr()  );
		fprintf( copyinfo_fp, "%d", n.id );
	}
	fprintf( tok_fp, "\n" );
	fprintf( copyinfo_fp, "\n" );

	CUString str; t.PrintStrRecurr( 0, str );
	fprintf( parse_fp, "%s\n", str.GetStr() );



	return true;
}


//////////////////////////////////////////////////////////////////////////////
bool CCopycatTest::PrintReorderedSent( CTree &t, FILE *tok_fp, FILE *parse_fp, FILE *rinfo_fp )
{
	int ls[NUM_MAX_NODE];
	int s;

	t.GetLexNodeList( ls, s, ROOT_ID );
	for( int i=0; i<s; i++ )	{
		CNode &n = t.node[ ls[i] ];
		CNode &p = t.node[ n.parent ];

		if( i > 0 )	{
			fprintf( tok_fp, " " );
			fprintf( rinfo_fp, " " );
		}
		//fprintf( tok_fp, "%s/%s", n.label.GetStr(), p.label.GetStr()  );
		CUString tmp = n.label;
		tmp.MakeToLower();
		fprintf( tok_fp, "%s", tmp.GetStr()  );
		fprintf( rinfo_fp, "%d", n.id );
	}
	fprintf( tok_fp, "\n" );
	fprintf( rinfo_fp, "\n" );

	CUString str; t.PrintStrRecurr( 0, str );
	fprintf( parse_fp, "%s\n", str.GetStr() );



	return true;
}


//////////////////////////////////////////////////////////////////////////////
// EOF


